package org.xx.armory.swing.components;

import javax.swing.*;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;

import static org.xx.armory.swing.ComponentUtils.shrink;

/**
 * 标尺。
 */
public class Ruler
        extends JComponent {
    /**
     * 横向标尺。
     */
    public static final int X_AXIS = 0;
    /**
     * 纵向标尺。
     */
    public static final int Y_AXIS = 1;

    private static final int DEFAULT_MIN_SIZE = 12;

    private final int axis;
    private final BorderType type;

    /**
     * 构造标尺对象。
     *
     * @param axis
     *         标尺的方向。
     * @param type
     *         标尺的类型。
     * @throws IllegalArgumentException
     *         如果参数{@code axis}既不是{@link #X_AXIS}也不是{@link #Y_AXIS}。
     */
    public Ruler(
            int axis,
            BorderType type
    ) {
        if (axis != X_AXIS && axis != Y_AXIS) {
            throw new IllegalArgumentException("illegal axis: " + axis);
        }

        this.axis = axis;
        this.type = type;

        setMinimumSize(new Dimension(DEFAULT_MIN_SIZE, DEFAULT_MIN_SIZE));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void updateUI() {
        setUI(UIManager.getUI(this));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getUIClassID() {
        return "Ruler";
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void paintComponent(
            Graphics graphics
    ) {
        super.paintComponent(graphics);

        // 计算出绘制区域。
        final Rectangle r = new Rectangle(getSize());
        shrink(r, getInsets());

        // 如果绘制区域和裁剪区域不相交则返回。
        if (!r.intersects(graphics.getClipBounds())) {
            return;
        }

        switch (this.axis) {
            case X_AXIS:
                // 画横线。
                int x1 = r.x;
                int x2 = r.x + r.width - 1;
                int y = r.y + r.height / 2;
                switch (this.type) {
                    case EMPTY:
                        break;
                    case SOLID:
                        drawHorizontal(graphics, getForeground(), x1, x2, y);
                        break;
                    case LOWERED:
                        drawHorizontal(graphics, getBackground().darker(), x1, x2, y);
                        drawHorizontal(graphics, getBackground().brighter(), x1, x2, y + 1);
                        break;
                    case RAISED:
                        drawHorizontal(graphics, getBackground().brighter(), x1, x2, y);
                        drawHorizontal(graphics, getBackground().darker(), x1, x2, y + 1);
                        break;
                    default:
                        break;
                }
                break;
            case Y_AXIS:
                // 画竖线。
                int x = r.x + r.width / 2;
                int y1 = r.y;
                int y2 = r.y + r.height - 1;
                switch (this.type) {
                    case EMPTY:
                        break;
                    case SOLID:
                        drawVertical(graphics, getForeground(), x, y1, y2);
                        break;
                    case LOWERED:
                        drawVertical(graphics, getBackground().darker(), x, y1, y2);
                        drawVertical(graphics, getBackground().brighter(), x + 1, y1, y2);
                        break;
                    case RAISED:
                        drawVertical(graphics, getBackground().brighter(), x, y1, y2);
                        drawVertical(graphics, getBackground().darker(), x + 1, y1, y2);
                        break;
                    default:
                        break;
                }
                break;
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Dimension getMaximumSize() {
        // 如果已设置最大尺寸，那么将最大尺寸的宽度或者高度调整为最大值，另一个方向不变。
        if (isMaximumSizeSet()) {
            final Dimension result = super.getMaximumSize();
            switch (this.axis) {
                case X_AXIS:
                    result.width = Integer.MAX_VALUE;
                    break;
                case Y_AXIS:
                    result.height = Integer.MAX_VALUE;
                    break;
                default:
                    break;
            }

            return result;
        }

        // 宽度或者高度调整为最大值，另一个方向取最小值。
        final Dimension minSize = getMinimumSize();
        switch (this.axis) {
            case X_AXIS:
                return new Dimension(Integer.MAX_VALUE, minSize.height);
            case Y_AXIS:
                return new Dimension(minSize.width, Integer.MAX_VALUE);
            default:
                return this.getPreferredSize();
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Dimension getMinimumSize() {
        // 如果已设置最小尺寸，那么返回最小尺寸，否则计算出最小尺寸。
        if (isMinimumSizeSet()) {
            return super.getMinimumSize();
        }

        // 通过字体计算出最小高度和宽度。
        return new Dimension(DEFAULT_MIN_SIZE, DEFAULT_MIN_SIZE);
    }

    /**
     * 使用指定的颜色画竖线。
     *
     * @param graphics
     *         绘图类。
     * @param color
     *         线条颜色。
     * @param x
     *         横座标。
     * @param y1
     *         第一个点的纵座标。
     * @param y2
     *         第二个点的纵座标。
     */
    protected final void drawVertical(
            Graphics graphics,
            Color color,
            int x,
            int y1,
            int y2
    ) {
        graphics.setColor(color);
        graphics.drawLine(x, y1, x, y2);
    }

    /**
     * 使用指定的颜色画横线。
     *
     * @param graphics
     *         绘图类。
     * @param color
     *         线条颜色。
     * @param x1
     *         第一个点的横座标。
     * @param x2
     *         第二个点的纵座标。
     * @param y
     *         纵座标。
     */
    protected final void drawHorizontal(
            Graphics graphics,
            Color color,
            int x1,
            int x2,
            int y
    ) {
        graphics.setColor(color);
        graphics.drawLine(x1, y, x2, y);
    }

    public final BorderType getType() {
        return this.type;
    }

    public final int getAxis() {
        return this.axis;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        return "Ruler{axis=" + this.axis + ",type=" + this.type + "}";
    }
}
